From 8362e46e1e5bfb75aa13c6997df2bc8767a31d9f Mon Sep 17 00:00:00 2001 From: "Karl O. Pinc" Date: Sun, 15 Sep 2024 23:17:55 -0500 Subject: [PATCH] Add ability to supply sql via a file --- src/pgwui_sql/templates/sql.mak | 5 ++-- src/pgwui_sql/templates/sql_edit.mak | 34 ++++++++++++++++++++++++- src/pgwui_sql/views/base.py | 33 +++++++++++++++++++++--- src/pgwui_sql/views/search_path_base.py | 19 ++++++++++++++ src/pgwui_sql/views/sql.py | 19 ++++++++++++++ tests/templates/test_templates.py | 1 + 6 files changed, 105 insertions(+), 6 deletions(-) diff --git a/src/pgwui_sql/templates/sql.mak b/src/pgwui_sql/templates/sql.mak index b5bc5a4..7fccb25 100644 --- a/src/pgwui_sql/templates/sql.mak +++ b/src/pgwui_sql/templates/sql.mak @@ -46,8 +46,9 @@ <%block name="action_success"> -

No errors, - from a file! +

No errors${ + f', from file ({filename})' if upload_sql else '' + }!

% if sql:
    diff --git a/src/pgwui_sql/templates/sql_edit.mak b/src/pgwui_sql/templates/sql_edit.mak index 7df2b00..9537cf8 100644 --- a/src/pgwui_sql/templates/sql_edit.mak +++ b/src/pgwui_sql/templates/sql_edit.mak @@ -62,12 +62,19 @@ window.alert('Problem showing the search_path: ' + error); }) }; + function toggle_sql_used(elem) { + sql_text = document.getElementById('sql_id'); + if (elem.checked) { + sql_text.style.backgroundColor = 'lightgrey'; + } else { + sql_text.style.backgroundColor = ''; + } + }; <%def name="sql_row(tab_index)"> <%self.lib:td_label for_id="search_path_id"> - search_path +<%def name="file_input_row(tab_index)"> + + <%self.lib:td_label for_id="upload_sql_id"> + Execute SQL from a file + + <%self.lib:td_input tab_index="${tab_index}" clas="search_path_data"> + + + + + <% tab_index.inc() %> + + + + <%def name="table_rows(tab_index)"> <%parent:table_rows tab_index="${tab_index}" args="tab_index"> ## A blank table row for spacing ${self.sql_row(tab_index)} + ${self.file_input_row(tab_index)} diff --git a/src/pgwui_sql/views/base.py b/src/pgwui_sql/views/base.py index aa46742..ccf2f1f 100644 --- a/src/pgwui_sql/views/base.py +++ b/src/pgwui_sql/views/base.py @@ -17,15 +17,17 @@ # . # -from wtforms.fields import TextAreaField import attrs import pgwui_core.core import pgwui_core.forms +import wtforms.fields @attrs.define(slots=False) class SQLInitialPost(pgwui_core.forms.UserInitialPost): sql = attrs.field(default='') + upload_sql = attrs.field(default=False) + sql_file = attrs.field(default=None) class SQLWTForm(pgwui_core.forms.AuthWTForm): @@ -33,7 +35,11 @@ class SQLWTForm(pgwui_core.forms.AuthWTForm): # We don't actually use the labels, wanting the template to # look (and render) like html, but I'll define them anyway # just to keep my hand in. - sql = TextAreaField('SQL:', id='sql_id') + sql = wtforms.fields.TextAreaField('SQL:', id='sql_id') + upload_sql = wtforms.fields.BooleanField( + 'Execute SQL from a file:', id='upload_sql_id') + sql_file = wtforms.fields.FileField( + 'File of SQL statements') @attrs.define(slots=False) @@ -45,6 +51,12 @@ class SQLForm(pgwui_core.forms.UploadFormBaseMixin, Attributes: uh The UploadHandler instance using the form ''' + sql = attrs.field(default='') + upload_sql = attrs.field(default=False) + sql_file = attrs.field(default=None) + sql_file_read = attrs.field(default=False) + filename = attrs.field(default=None) + def read(self): ''' Read form data from the client @@ -54,7 +66,22 @@ class SQLForm(pgwui_core.forms.UploadFormBaseMixin, super().read() # Read our own data - if self._form.sql.data is None: + self['filename'] = '' + self['upload_sql'] = self._form.upload_sql.data + if self['upload_sql']: + self['sql_file_read'] = False # Parent class breaks defaulting + post = self.uh.request.POST + self['sql'] = '' + if self['action']: + if self._form.sql_file.data != '': + if hasattr(post['sql_file'], 'filename'): + self['filename'] = post['sql_file'].filename + if hasattr(post['sql_file'], 'file'): + fh = post['sql_file'].file + self['sql'] = fh.read().decode() + fh.close() + self['sql_file_read'] = True + elif self._form.sql.data is None: self['sql'] = '' else: self['sql'] = self._form.sql.data diff --git a/src/pgwui_sql/views/search_path_base.py b/src/pgwui_sql/views/search_path_base.py index 0c319c9..00cc0c3 100644 --- a/src/pgwui_sql/views/search_path_base.py +++ b/src/pgwui_sql/views/search_path_base.py @@ -23,6 +23,11 @@ import pgwui_core.forms import pgwui_sql.views.base import pgwui_sql.exceptions as sql_ex +from pgwui_core.constants import ( + CHECKED, + UNCHECKED, +) + @attrs.define(slots=False) class SQLEditForm(pgwui_sql.views.base.SQLForm): @@ -31,6 +36,20 @@ class SQLEditForm(pgwui_sql.views.base.SQLForm): def read(self): super().read() self['action'] = 'u' + self['upload_sql'] = self._form.upload_sql.data + + def write(self, result, errors): + ''' + Return the dict Pyramid uses to render the form. + ''' + response = super().write(result, errors) + + if self['upload_sql']: + response['upload_sql'] = CHECKED + else: + response['upload_sql'] = UNCHECKED + + return response # Utility functions diff --git a/src/pgwui_sql/views/sql.py b/src/pgwui_sql/views/sql.py index 5ea0335..a7ab78a 100644 --- a/src/pgwui_sql/views/sql.py +++ b/src/pgwui_sql/views/sql.py @@ -100,10 +100,29 @@ class SQLResultsHandler(pgwui_core.core.SessionDBHandler): ''' response = super().write(result, errors) response['search_path'] = self.search_path + response['upload_sql'] = self.uf['upload_sql'] + response['filename'] = self.uf['filename'] response['report_success'] = (not response['errors'] and self.uf['action'] != '') return response + def val_input(self): + ''' + Validate input needed beyond that required to connect to the db. + + Returns: + A list of Error instances + ''' + uf = self.uf + errors = super().val_input() + + if uf['upload_sql'] and not uf['sql_file_read']: + errors.append(sql_ex.NoFileError( + 'No SQL supplied', + descr=('The execute sql from a file checkbox was' + ' checked, but a file containing SQL was not chosen'))) + return errors + def get_data(self): '''Return no data. Data is in lines and we have no lines. ''' diff --git a/tests/templates/test_templates.py b/tests/templates/test_templates.py index 6bb5e49..68ac7e7 100644 --- a/tests/templates/test_templates.py +++ b/tests/templates/test_templates.py @@ -46,6 +46,7 @@ stock_template_args = { 'csrf_token': 'somecsrftoken', 'sql': 'select 1;', 'search_path': '"$user", somedb', + 'upload_sql': True } # The templates to test -- 2.34.1